#include "pp_parser.h"
#include "pp_tags.h"

#include <sstream>

namespace pp
{
    std::string JoinToken(const std::vector<std::shared_ptr<TokenInfo> >& tokens, uint32_t start, uint32_t end)
    {
        std::stringstream ss;
        for (uint32_t i = start; i < end; i++)
        {
            ss << tokens[i]->GetTokenValue() << " ";
        }
        return ss.str();
    }

    Parser::Parser() : m_u32Pos(0)
    {
        m_fnState = &Parser::OnStateInit;
    }

    // 重置数据
    void Parser::Reset()
    {
        m_u32Pos = 0;
        m_fnState = &Parser::OnStateInit;
        m_oStructs.clear();
    }

    // 解析字符串
    void Parser::Parse(const std::string& data)
    {
        if (!m_pParseHandler) throw std::runtime_error("no parse handler set");

        Tokenizer tk;
        std::vector<std::shared_ptr<TokenInfo> >& tokens = tk.Parse(data);

        Reset();

        for (size_t i = 0; i < tokens.size(); i++)
        {
            (this->*m_fnState)(i, tokens[i], tokens);
        }
    }
    // 解析文件
    void Parser::ParseFile(const std::string& fileName)
    {
        if (!m_pParseHandler) throw std::runtime_error("no parse handler set");

        Tokenizer tk;
        std::vector<std::shared_ptr<TokenInfo> >& tokens = tk.ParseFile(fileName);

        Reset();

        for (size_t i = 0; i < tokens.size(); i++)
        {
            (this->*m_fnState)(i, tokens[i], tokens);
        }
    }

    void Parser::OnStateInit(uint32_t pos, const std::shared_ptr<TokenInfo>& token,
        const std::vector<std::shared_ptr<TokenInfo> >& tokens)
    {
        const std::string& ttype = token->GetTokenType();
        const std::string& val = token->GetTokenValue();

        if (ttype == TOKEN_TYPE_TEXT)
        {
            if (val == "const")
            {
                m_fnState = &Parser::OnStateConst;
            }
            else if (val == "enum" || val == "module" || val == "struct" || val == "union" || val == "message" || val == "oneof")
            {
                m_fnState = &Parser::OnStateStruct;
            }
            else if (val == "package")
            {
                m_fnState = &Parser::OnStatePackage;
            }
            else if (val == "option")
            {
                m_fnState = &Parser::OnStateOption;
            }
            else if (val == "import")
            {
                m_fnState = &Parser::OnStateImport;
            }
        }
        else if (ttype == TOKEN_TYPE_OP && val == "}")
        {
            EndElement();
            m_u32Pos = pos + 1;
        }
        else if (ttype == TOKEN_TYPE_COMMENT)
        {
            m_u32Pos = pos + 1;
        }
    }

    void Parser::OnStateStruct(uint32_t pos, const std::shared_ptr<TokenInfo>& token,
        const std::vector<std::shared_ptr<TokenInfo> >& tokens)
    {
        if (token->GetTokenType() != TOKEN_TYPE_OP) return;
        if (token->GetTokenValue() != "{" || pos - m_u32Pos != 2) throw std::runtime_error("message format error:" + JoinToken(tokens, m_u32Pos, pos));

        std::map<std::string, std::string> attrs;
        attrs["name"] = tokens[m_u32Pos + 1]->GetTokenValue();
        if (m_u32Pos > 0)
        {
            uint32_t cpos = m_u32Pos - 1;
            if (tokens[cpos]->GetTokenType() == TOKEN_TYPE_COMMENT) attrs["desc"] = tokens[cpos]->GetTokenValue();
        }

        std::string name = tokens[m_u32Pos]->GetTokenValue();
        m_pParseHandler->StartElement(name, attrs);

        if (name == "module")
        {
            m_fnState = &Parser::OnStateInit;
        }
        else if (name == "struct" || name == "union" || name == "message" || name == "oneof")
        {
            m_fnState = &Parser::OnStateField;
        }
        else if (name == "enum")
        {
            m_fnState = &Parser::OnStateMacro;
        }
        m_u32Pos = pos + 1;
        m_oStructs.push_back(name);
    }

    void Parser::OnStatePackage(uint32_t pos, const std::shared_ptr<TokenInfo>& token,
        const std::vector<std::shared_ptr<TokenInfo> >& tokens)
    {
        if (token->GetTokenType() != TOKEN_TYPE_OP || token->GetTokenValue() != ";") return;

        if (pos - m_u32Pos != 2 || tokens[m_u32Pos + 1]->GetTokenType() != TOKEN_TYPE_TEXT)
        {
            throw std::runtime_error("package format error:" + JoinToken(tokens, m_u32Pos, pos));
        }

        std::map<std::string, std::string> attrs;
        attrs["name"] = tokens[m_u32Pos + 1]->GetTokenValue();
        // 注释
        if (tokens.size() > pos + 1)
        {
            if (tokens[pos + 1]->GetTokenType() == TOKEN_TYPE_COMMENT) attrs["desc"] = tokens[pos + 1]->GetTokenValue();
        }
        m_pParseHandler->StartElement("package", attrs);
        m_fnState = &Parser::OnStateInit;
        m_u32Pos = pos + 1;
        m_pParseHandler->EndElement("package");
    }

    void Parser::OnStateOption(uint32_t pos, const std::shared_ptr<TokenInfo>& token,
        const std::vector<std::shared_ptr<TokenInfo> >& tokens)
    {
        if (token->GetTokenType() != TOKEN_TYPE_OP || token->GetTokenValue() != ";") return;

        if (pos - m_u32Pos != 4 || tokens[m_u32Pos + 1]->GetTokenType() != TOKEN_TYPE_TEXT ||
            tokens[m_u32Pos + 2]->GetTokenType() != TOKEN_TYPE_OP || tokens[m_u32Pos + 2]->GetTokenValue() != "=" ||
            (tokens[m_u32Pos + 3]->GetTokenType() != TOKEN_TYPE_QUOTES && tokens[m_u32Pos + 3]->GetTokenType() != TOKEN_TYPE_TEXT))
        {
            throw std::runtime_error("option format error:" + JoinToken(tokens, m_u32Pos, pos));
        }

        std::map<std::string, std::string> attrs;
        attrs["name"] = tokens[m_u32Pos + 1]->GetTokenValue();
        attrs["value"] = tokens[m_u32Pos + 3]->GetTokenValue();
        // 注释
        if (tokens.size() > pos + 1)
        {
            if (tokens[pos + 1]->GetTokenType() == TOKEN_TYPE_COMMENT) attrs["desc"] = tokens[pos + 1]->GetTokenValue();
        }
        m_pParseHandler->StartElement("option", attrs);
        m_fnState = &Parser::OnStateInit;
        m_u32Pos = pos + 1;
        m_pParseHandler->EndElement("option");
    }

    void Parser::OnStateImport(uint32_t pos, const std::shared_ptr<TokenInfo>& token,
        const std::vector<std::shared_ptr<TokenInfo> >& tokens)
    {
        if (token->GetTokenType() != TOKEN_TYPE_OP || token->GetTokenValue() != ";") return;

        if (pos - m_u32Pos != 2 || (tokens[m_u32Pos + 1]->GetTokenType() != TOKEN_TYPE_QUOTES && tokens[m_u32Pos + 1]->GetTokenType() != TOKEN_TYPE_TEXT))
        {
            throw std::runtime_error("import format error:" + JoinToken(tokens, m_u32Pos, pos));
        }

        std::map<std::string, std::string> attrs;
        attrs["value"] = tokens[m_u32Pos + 1]->GetTokenValue();
        m_pParseHandler->StartElement("import", attrs);
        m_fnState = &Parser::OnStateInit;
        m_u32Pos = pos + 1;
        m_pParseHandler->EndElement("import");
    }

    void Parser::OnStateConst(uint32_t pos, const std::shared_ptr<TokenInfo>& token,
        const std::vector<std::shared_ptr<TokenInfo> >& tokens)
    {
        if (token->GetTokenType() != TOKEN_TYPE_OP || token->GetTokenValue() != ";") return;

        if (pos - m_u32Pos != 5 || tokens[m_u32Pos + 1]->GetTokenType() != TOKEN_TYPE_TEXT || tokens[m_u32Pos + 2]->GetTokenType() != TOKEN_TYPE_TEXT ||
            tokens[m_u32Pos + 3]->GetTokenType() != TOKEN_TYPE_OP || tokens[m_u32Pos + 3]->GetTokenValue() != "=" ||
            (tokens[m_u32Pos + 4]->GetTokenType() != TOKEN_TYPE_TEXT && tokens[m_u32Pos + 4]->GetTokenType() != TOKEN_TYPE_QUOTES))
        {
            throw std::runtime_error("const format error:" + JoinToken(tokens, m_u32Pos, pos));
        }

        std::map<std::string, std::string> attrs;
        attrs["type"] = tokens[m_u32Pos + 1]->GetTokenValue();
        attrs["name"] = tokens[m_u32Pos + 2]->GetTokenValue();
        attrs["value"] = tokens[m_u32Pos + 4]->GetTokenValue();
        // 注释
        if (tokens.size() > pos + 1)
        {
            if (tokens[pos + 1]->GetTokenType() == TOKEN_TYPE_COMMENT) attrs["desc"] = tokens[pos + 1]->GetTokenValue();
        }
        m_pParseHandler->StartElement("macro", attrs);
        m_fnState = &Parser::OnStateInit;
        m_u32Pos = pos + 1;
        m_pParseHandler->EndElement("macro");
    }

    void Parser::OnStateField(uint32_t pos, const std::shared_ptr<TokenInfo>& token,
        const std::vector<std::shared_ptr<TokenInfo> >& tokens)
    {
        const std::string& ttype = token->GetTokenType();
        const std::string& val = token->GetTokenValue();

        if (ttype == TOKEN_TYPE_OP && val == ";")
        {
            // 结构体字段定义例子：int x = 1; 或 string y = 1; 或 repeated string y = 1;
            // 长度最少是 4，若是repeated或者repeat的话，则至少是5
            uint32_t tokenNum = pos - m_u32Pos;
            if (tokenNum < 4) throw std::runtime_error("field format error:" + JoinToken(tokens, m_u32Pos, pos));
            std::map<std::string, std::string> attrs;
            // 字段类型
            const std::string& ftype = tokens[m_u32Pos]->GetTokenValue();
            if (ftype == "repeated" || ftype == "repeat")
            {
                if (tokenNum != 5 || tokens[m_u32Pos]->GetTokenType() != TOKEN_TYPE_TEXT ||
                    tokens[m_u32Pos + 1]->GetTokenType() != TOKEN_TYPE_TEXT || tokens[m_u32Pos + 2]->GetTokenType() != TOKEN_TYPE_TEXT ||
                    tokens[m_u32Pos + 3]->GetTokenType() != TOKEN_TYPE_OP || tokens[m_u32Pos + 3]->GetTokenValue() != "=" ||
                    tokens[m_u32Pos + 4]->GetTokenType() != TOKEN_TYPE_TEXT)
                {
                    throw std::runtime_error("field format error:" + JoinToken(tokens, m_u32Pos, pos));
                }
                attrs["type"] = "array";                                    // 字段类型
                attrs["subtype"] = tokens[m_u32Pos + 1]->GetTokenValue();   // 数组子类型
                attrs["name"] = tokens[m_u32Pos + 2]->GetTokenValue();      // 字段名
                attrs["tag"] = tokens[m_u32Pos + 4]->GetTokenValue();       // 字段标签
            }
            else
            {
                if (tokenNum != 4 || tokens[m_u32Pos]->GetTokenType() != TOKEN_TYPE_TEXT ||
                    tokens[m_u32Pos + 1]->GetTokenType() != TOKEN_TYPE_TEXT ||
                    tokens[m_u32Pos + 2]->GetTokenType() != TOKEN_TYPE_OP || tokens[m_u32Pos + 2]->GetTokenValue() != "=" ||
                    tokens[m_u32Pos + 3]->GetTokenType() != TOKEN_TYPE_TEXT)
                {
                    throw std::runtime_error("field define:" + JoinToken(tokens, m_u32Pos, pos));
                }
                attrs["type"] = ftype;                                  // 字段类型
                attrs["name"] = tokens[m_u32Pos + 1]->GetTokenValue();  // 字段名
                attrs["tag"] = tokens[m_u32Pos + 3]->GetTokenValue();   // 字段标签
            }
            // 看是否有tag，tag的例子 `json:"email,omitempty" pp:"default:45;size:200"`
            uint32_t exti = 1;
            if (exti + pos < tokens.size())
            {
                if (tokens[exti + pos]->GetTokenType() == TOKEN_TYPE_TAGS)
                {
                    // 解析tags
                    TagParser tagParser;
                    tagParser.Parse(tokens[exti + pos]->GetTokenValue(), attrs);
                    exti++;
                }
            }
            // 是否有注释
            if (exti + pos < tokens.size())
            {
                if (tokens[exti + pos]->GetTokenType() == TOKEN_TYPE_COMMENT)
                {
                    attrs["desc"] = tokens[exti + pos]->GetTokenValue();
                }
            }
            m_pParseHandler->StartElement("field", attrs);
            m_u32Pos = pos + 1;
            m_pParseHandler->EndElement("field");
        }
        else if (ttype == TOKEN_TYPE_OP && val == "}")
        {
            EndElement();
            m_fnState = &Parser::OnStateInit;
            m_u32Pos = pos + 1;
        }
        else if (ttype == TOKEN_TYPE_TAGS)
        {
            m_u32Pos = pos + 1;
        }
        else if (ttype == TOKEN_TYPE_COMMENT)
        {
            m_u32Pos = pos + 1;
        }
    }

    void Parser::OnStateMacro(uint32_t pos, const std::shared_ptr<TokenInfo>& token,
        const std::vector<std::shared_ptr<TokenInfo> >& tokens)
    {
        const std::string& ttype = token->GetTokenType();
        const std::string& val = token->GetTokenValue();

        if (ttype == TOKEN_TYPE_OP && (val == "," || val == ";"))
        {
            // 枚举定义例子：x = 1; 或 x = 1,
            if (pos - m_u32Pos != 3 || tokens[m_u32Pos]->GetTokenType() != TOKEN_TYPE_TEXT ||
                tokens[m_u32Pos + 1]->GetTokenType() != TOKEN_TYPE_OP || tokens[m_u32Pos + 1]->GetTokenValue() != "=" ||
                tokens[m_u32Pos + 2]->GetTokenType() != TOKEN_TYPE_TEXT)
            {
                throw std::runtime_error("macro format error:" + JoinToken(tokens, m_u32Pos, pos));
            }
            std::map<std::string, std::string> attrs;
            attrs["name"] = tokens[m_u32Pos]->GetTokenValue();
            attrs["value"] = tokens[m_u32Pos + 2]->GetTokenValue();
            // 注释
            if (tokens.size() > pos + 1)
            {
                if (tokens[pos + 1]->GetTokenType() == TOKEN_TYPE_COMMENT) attrs["desc"] = tokens[pos + 1]->GetTokenValue();
            }
            m_pParseHandler->StartElement("macro", attrs);
            m_u32Pos = pos + 1;
            m_pParseHandler->EndElement("macro");
        }
        else if (ttype == TOKEN_TYPE_OP && val == "}")
        {
            EndElement();
            m_fnState = &Parser::OnStateInit;
            m_u32Pos = pos + 1;
        }
        else if (ttype == TOKEN_TYPE_COMMENT)
        {
            m_u32Pos = pos + 1;
        }
    }

    void Parser::EndElement()
    {
        if (m_oStructs.empty()) return;

        std::string name = m_oStructs.back();
        m_oStructs.pop_back();
        m_pParseHandler->EndElement(name);
    }
};
